package com.yuyou.fn.settlement.service.impl;

import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.toolkit.IdWorker;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.BeanUtils;
import com.yuyou.fn.common.util.BigDecimals;
import com.yuyou.fn.common.util.TimeUtils;
import com.yuyou.fn.settlement.constant.*;
import com.yuyou.fn.settlement.entity.*;
import com.yuyou.fn.settlement.service.*;
import org.apache.commons.lang3.StringUtils;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by wens on 2017/3/24.
 */
@Service
public class SettlementServiceImpl implements ISettlementService {


    @Resource
    private IMainAccountService mainAccountService ;

    @Resource
    private IChangeRecordService changeRecordService ;

    @Resource
    private IIncomeCategoryService incomeCategoryService ;

    @Resource
    private IFeeService feeService ;

    @Resource
    private IFeeCategoryService feeCategoryService ;

    @Resource
    private ITradePropService tradePropService ;

    @Resource
    private IRelFeeCategoryIncomeCategoryService relFeeCategoryIncomeCategoryService ;

    @Resource
    private IBalanceChangeService balanceChangeService;

    @Resource
    private Redisson redisson ;

    @Transactional
    @Override
    public void bookCost(Long mainAccountId , Long feeCategoryId , Long relMainAccountId, BigDecimal amount, String remark ,Date date) {
        List<MainAccount> mainAccountList = mainAccountService.findByIds(Arrays.asList(mainAccountId, relMainAccountId), "mainAccountId" ,"name");
        FeeCategory feeCategory=feeCategoryService.findById(feeCategoryId,"feeCategoryId","name");
        Map<Long,MainAccount> mainAccountMap=BeanUtils.toMap(mainAccountList,"mainAccountId");
        Fee fee = new Fee();
        fee.setAmount(amount);
        fee.setFeeCategoryId(feeCategoryId);
        fee.setFeeCategoryName(feeCategory==null?null:feeCategory.getName());
        fee.setMainAccountId(mainAccountId);
        fee.setReceiverMainAccountId(relMainAccountId);
        fee.setRemark(remark);
        fee.setStatus(FeeStatus.AUDITED.ordinal());
        fee.setShareStatus(FeeShareStatus.SHAREED.ordinal());
        fee.setCreateTime(TimeUtils.now());
        fee.setUpdateTime(TimeUtils.now());
        fee.setReceiverMainAccountName(mainAccountMap.get(relMainAccountId).getName());
        feeService.insertSelective(fee);

        RelFeeCategoryIncomeCategory relFeeCategoryIncomeCategory = relFeeCategoryIncomeCategoryService.findById(feeCategoryId);
        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("feeId" , String.valueOf( fee.getFeeId() ) );
        book( fee.getFeeId() ,date , mainAccountId ,amount ,0,remark , Subjects.COST  ,feeCategoryId ,relMainAccountId ,amount ,0  , remark ,Subjects.FUTURE_INCOME , relFeeCategoryIncomeCategory.getIncomeCategoryId()  , tradeProps );
        book( fee.getFeeId() ,date , relMainAccountId ,amount ,1,remark , Subjects.FUTURE_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() ,relMainAccountId ,amount ,0 , remark ,Subjects.REAL_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() , tradeProps );


    }


    @Transactional
    @Override
    public void bookFeeIncome(Long mainAccountId , Long feeCategoryId , Long relMainAccountId, BigDecimal amount, String remark , Long feeId , Date feeTime ) {
        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("feeId" , String.valueOf( feeId ) );
        RelFeeCategoryIncomeCategory relFeeCategoryIncomeCategory = relFeeCategoryIncomeCategoryService.findById(feeCategoryId);
        book( feeId ,feeTime,mainAccountId ,amount ,0,remark , Subjects.DEFERRED_COST  ,feeCategoryId ,relMainAccountId ,amount ,0  , remark ,Subjects.FUTURE_INCOME , relFeeCategoryIncomeCategory.getIncomeCategoryId()  , tradeProps );

    }

    @Transactional
    @Override
    public void shareFee(Long mainAccountId , Long feeCategoryId ,Long relMainAccountId , BigDecimal amount , String remark, Long feeId , Date feeTime ) {
        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("feeId" , String.valueOf( feeId ) );
        RelFeeCategoryIncomeCategory relFeeCategoryIncomeCategory = relFeeCategoryIncomeCategoryService.findById(feeCategoryId);
        book(feeId ,feeTime , mainAccountId , amount ,1,remark , Subjects.DEFERRED_COST ,feeCategoryId  ,mainAccountId ,amount ,0 , remark ,Subjects.COST ,feeCategoryId , tradeProps );
        book( feeId ,feeTime , relMainAccountId ,amount ,1,remark , Subjects.FUTURE_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() ,relMainAccountId ,amount ,0 , remark ,Subjects.REAL_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() , tradeProps );
    }

    @Transactional
    @Override
    public void bookProductDeal(Long mainAccountId, Long feeCategoryId, Long relMainAccountId , BigDecimal amount, String remark , Long orderItemId ) {
        List<MainAccount> mainAccountList = mainAccountService.findByIds(Arrays.asList(mainAccountId, relMainAccountId), "mainAccountId" ,"name");
        FeeCategory feeCategory=feeCategoryService.findById(feeCategoryId,"feeCategoryId","name");
        Map<Long,MainAccount> mainAccountMap=BeanUtils.toMap(mainAccountList,"mainAccountId");
        Fee fee = new Fee();
        fee.setAmount(amount);
        fee.setFeeCategoryId(feeCategoryId);
        fee.setMainAccountId(mainAccountId);
        fee.setReceiverMainAccountId(relMainAccountId);
        fee.setReceiverMainAccountName(mainAccountMap.get(relMainAccountId).getName());
        fee.setRemark(remark);
        fee.setBusId(orderItemId);
        fee.setStatus(FeeStatus.AUDITED.ordinal());
        fee.setShareStatus(FeeShareStatus.NOT_SHARE.ordinal());
        fee.setCreateTime(TimeUtils.now());
        fee.setUpdateTime(TimeUtils.now());
        fee.setFeeCategoryName(feeCategory==null?null:feeCategory.getName());
        feeService.insertSelective(fee);

        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("feeId" , String.valueOf( fee.getFeeId() ) );
        RelFeeCategoryIncomeCategory relFeeCategoryIncomeCategory = relFeeCategoryIncomeCategoryService.findById(feeCategoryId);
        book( fee.getFeeId(),TimeUtils.now(),mainAccountId ,amount ,0,remark , Subjects.COST  ,feeCategoryId ,relMainAccountId ,amount ,0  , remark ,Subjects.FUTURE_INCOME , relFeeCategoryIncomeCategory.getIncomeCategoryId() , tradeProps );
        book( fee.getFeeId() ,TimeUtils.now() , relMainAccountId ,amount ,1,remark , Subjects.FUTURE_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() ,relMainAccountId ,amount ,0 , remark ,Subjects.REAL_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() , tradeProps );
        decreaseBalanceWithNotCheck(mainAccountId,amount,"购买商品服务");
    }

    @Transactional
    @Override
    public void bookLeaseDeal(Long mainAccountId, Long relMainAccountId, BigDecimal amount, String remark, Date shareStart, Date shareEnd, Long orderItemId) {
        List<MainAccount> mainAccountList = mainAccountService.findByIds(Arrays.asList(mainAccountId, relMainAccountId), "mainAccountId" ,"name");
        Map<Long,MainAccount> mainAccountMap=BeanUtils.toMap(mainAccountList,"mainAccountId");
        Fee fee = new Fee();
        fee.setAmount(amount);
        fee.setFeeCategoryId(FeeCategoryEnum.LEAVE.id);
        FeeCategory feeCategory=feeCategoryService.findById(FeeCategoryEnum.LEAVE.id,"feeCategoryId","name");
        fee.setMainAccountId(mainAccountId);
        fee.setReceiverMainAccountName(mainAccountMap.get(relMainAccountId).getName());
        fee.setReceiverMainAccountId(relMainAccountId);
        fee.setRemark(remark);
        fee.setBusId(orderItemId);
        fee.setStatus(FeeStatus.AUDITED.ordinal());
        fee.setShareStatus(FeeShareStatus.NOT_SHARE.ordinal());
        fee.setShareStart(shareStart);
        fee.setShareEnd(shareEnd);
        fee.setCreateTime(TimeUtils.now());
        fee.setUpdateTime(TimeUtils.now());
        fee.setFeeCategoryName(feeCategory==null?null:feeCategory.getName());
        feeService.insertSelective(fee);

        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("feeId" , String.valueOf( fee.getFeeId() ) );
        RelFeeCategoryIncomeCategory relFeeCategoryIncomeCategory = relFeeCategoryIncomeCategoryService.findById(FeeCategoryEnum.LEAVE.id);
        book( fee.getFeeId(),TimeUtils.now(),mainAccountId ,amount ,0,remark , Subjects.DEFERRED_COST  ,FeeCategoryEnum.LEAVE.id ,relMainAccountId ,amount ,0  , remark ,Subjects.FUTURE_INCOME , relFeeCategoryIncomeCategory.getIncomeCategoryId() , tradeProps );

        decreaseBalanceWithNotCheck(mainAccountId,amount,"支付租赁费用");
    }

    @Transactional
    @Override
    public void bookRefundForDeal(BigDecimal amount, String remark , Long orderItemId ) {

        Fee fee = feeService.findFeeByBudId(orderItemId);
        if(fee == null ){
            throw new BusException("无法处理退款");
        }

        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("feeId" , String.valueOf( fee.getFeeId() ) );
        RelFeeCategoryIncomeCategory relFeeCategoryIncomeCategory = relFeeCategoryIncomeCategoryService.findById(fee.getFeeCategoryId());
        book( fee.getFeeId(),TimeUtils.now() ,fee.getMainAccountId() , amount.multiply(BigDecimal.valueOf(-1)) ,0,remark , Subjects.COST ,fee.getFeeCategoryId()  ,fee.getReceiverMainAccountId() ,amount.multiply(BigDecimal.valueOf(-1)) ,0  , remark ,Subjects.REAL_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId()  ,  tradeProps );
    }

    @Transactional
    @Override
    public void bookIncomeForCourse(Long mainAccountId, Long relMainAccountId, BigDecimal amount, String className ,Long classId, Long regId ) {
        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("classId" , String.valueOf(classId));
        tradeProps.put("regId" , String.valueOf(regId));
        List<ChangeRecord> changeRecordList = book(regId,TimeUtils.now(),mainAccountId, amount , 0 , "【" + className + "】收入", Subjects.FUTURE_INCOME, IncomeCategoryEnum.COURSE_INCOME.id , relMainAccountId, amount,0, "购买【" + className + "】", Subjects.COST,FeeCategoryEnum.OTHER_FEE.id , tradeProps );
        if(changeRecordList == null && changeRecordList.size() ==2 ){
            markBookToBalance(changeRecordList.get(1));
        }
    }


    @Transactional
    @Override
    public void bookRefundForCourse(Long mainAccountId, Long relMainAccountId, String remark, Long classId , BigDecimal refundAmount ,List<Long> classLectureIds, Long regId, Long studentId ) {

        List<ChangeRecord> changeRecordList = changeRecordService.findChangeRecordByTrackingIdSubjectCategoryId(regId, Subjects.FUTURE_INCOME , IncomeCategoryEnum.COURSE_INCOME.id);
        List<ChangeRecord>  changeRecordListOfDeb = new ArrayList<>(changeRecordList.size());
        for(ChangeRecord changeRecord : changeRecordList ){
            if(changeRecord.getDirection() == 1 ){
                changeRecordListOfDeb.add(changeRecord);
            }
        }

        List<Long> tradeIds = BeanUtils.toList(changeRecordListOfDeb,"tradeId");
        List<TradeProp> classLectureIdPropList  = tradePropService.findValueByTradeIdsName(tradeIds ,"classLectureId");
        Map<Long,Long> tradeId2ClassLectureId = new HashMap<>();
        for(TradeProp tradeProp : classLectureIdPropList ){
            tradeId2ClassLectureId.put(tradeProp.getTradeId(),Long.valueOf( tradeProp.getValue() ));
        }

        //退营收
        BigDecimal consumeAmount  = BigDecimal.ZERO ;
        List<Long> consumeClassLectureIds = new ArrayList<>(classLectureIds.size());
        for(ChangeRecord changeRecord : changeRecordListOfDeb ){
            Long classLectureId = tradeId2ClassLectureId.get(changeRecord.getTradeId());
            if(classLectureIds.contains(classLectureId)){
                consumeClassLectureIds.add(classLectureId);
                consumeAmount = consumeAmount.add(changeRecord.getAmount());
            }
        }

        if(!consumeClassLectureIds.isEmpty()){
            // 消耗红冲金额
            bookRefundForCourse2(mainAccountId, relMainAccountId, BigDecimals.min( refundAmount, consumeAmount ), remark, classId, consumeClassLectureIds , regId, studentId , true );
        }

        if( BigDecimals.compare(refundAmount,consumeAmount) > 0 ){
            //预收红冲金额  = refundAmount - 消耗红冲金额
            bookRefundForCourse2(mainAccountId, relMainAccountId, refundAmount.subtract(consumeAmount) , remark, classId, Lists.newArrayList( Collections2.filter(classLectureIds, id -> !consumeClassLectureIds.contains(id)) ), regId, studentId , false );
        }

        increaseBalance(relMainAccountId , refundAmount ,"课程退费");
    }

    private void bookRefundForCourse2(Long mainAccountId, Long relMainAccountId, BigDecimal amount, String remark, Long classId, List<Long> classLectureIds, Long regId, Long studentId, boolean isConsume ) {
        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("classId" , String.valueOf(classId));
        tradeProps.put("regId" , String.valueOf(regId));
        tradeProps.put("studentId" , String.valueOf(studentId));
        tradeProps.put("refundClassLectureIds" , StringUtils.join(classLectureIds,","));
         book( regId, TimeUtils.now(),mainAccountId, amount.multiply(BigDecimal.valueOf(-1)),0 , "【" + remark + "】退款", isConsume ? Subjects.REAL_INCOME : Subjects.FUTURE_INCOME, IncomeCategoryEnum.COURSE_INCOME.id , relMainAccountId, amount,0 , "【" + remark + "】退款" , Subjects.FUTURE_INCOME , IncomeCategoryEnum.OTHER_INCOME.id , tradeProps );
        List<ChangeRecord> changeRecordList = book(classId,TimeUtils.now(),relMainAccountId, amount,1, "【" + remark + "】退款", Subjects.FUTURE_INCOME, IncomeCategoryEnum.OTHER_INCOME.id , relMainAccountId, amount , 0 , remark , Subjects.REAL_INCOME ,IncomeCategoryEnum.OTHER_INCOME.id , tradeProps );
        markBookToBalance(changeRecordList.get(1));
    }

    /**
     * 标记已结算
     * @param changeRecord
     */
    private void markBookToBalance(ChangeRecord changeRecord) {

        //changeRecord.setSettleStatus(1);
        ChangeRecord update = new ChangeRecord();
        update.setChangeRecordId(changeRecord.getChangeRecordId());
        update.setSettleStatus(1);
        changeRecordService.updateSelectiveById(update);

    }


    /**
     *
     * @param trackingId
     * @param mainAccountId
     * @param amount
     * @param direction
     * @param remark
     * @param subject
     * @param relMainAccountId
     * @param relAmount
     * @param relDirection
     * @param relRemark
     * @param relSubject
     * @param tradeProps
     * @return
     */
    private List<ChangeRecord> book(Long trackingId , Date time , Long mainAccountId , BigDecimal amount ,Integer direction , String remark, String subject ,Long categoryId  , Long relMainAccountId  , BigDecimal relAmount ,Integer relDirection , String relRemark , String relSubject , Long relCategoryId , Map<String,String> tradeProps ) {

        Long tradeId = IdWorker.getId();

        List<MainAccount> mainAccountList = mainAccountService.findByIds(Arrays.asList(mainAccountId, relMainAccountId));
        Map<Long,MainAccount> mainAccountMap = BeanUtils.toMap(mainAccountList,"mainAccountId") ;
        if( !mainAccountMap.containsKey(mainAccountId) || !mainAccountMap.containsKey(relMainAccountId)){
            return Collections.EMPTY_LIST ;
        }

        if(time == null ){
            time = TimeUtils.now();
        }
        ChangeRecord changeRecord = new ChangeRecord();
        changeRecord.setAmount(amount);
        changeRecord.setMainAccountId(mainAccountId);
        changeRecord.setSubject(subject);
        changeRecord.setTrackingId(trackingId);
        changeRecord.setTradeId(tradeId);
        changeRecord.setParentMainAccountId(mainAccountMap.get(mainAccountId).getParentMainAccountId());
        changeRecord.setRemark(remark);
        changeRecord.setEffectTime(time);
        //tag
        changeRecord.setCreateTime(TimeUtils.now());
        changeRecord.setUpdateTime(TimeUtils.now());
        changeRecord.setSettleStatus(0);
        changeRecord.setDirection(direction);
        changeRecord.setCategoryId(categoryId);

        ChangeRecord relChangeRecord = new ChangeRecord();
        relChangeRecord.setAmount(relAmount);
        relChangeRecord.setMainAccountId(relMainAccountId);
        relChangeRecord.setSubject(relSubject);
        relChangeRecord.setTrackingId(trackingId);
        relChangeRecord.setTradeId(tradeId);
        relChangeRecord.setParentMainAccountId(mainAccountMap.get(relMainAccountId).getParentMainAccountId());
        relChangeRecord.setRemark(relRemark);
        relChangeRecord.setEffectTime(time);
        //tag
        relChangeRecord.setCreateTime(TimeUtils.now());
        relChangeRecord.setUpdateTime(TimeUtils.now());
        relChangeRecord.setSettleStatus(0);
        relChangeRecord.setDirection(relDirection);
        relChangeRecord.setCategoryId(relCategoryId);
        changeRecordService.insertBatch(Arrays.asList(changeRecord,relChangeRecord ));

        if(tradeProps != null ){
            List<TradeProp> tradePropList = new ArrayList<>(tradeProps.size());
            for(Map.Entry<String,String> entry : tradeProps.entrySet() ){
                TradeProp tradeProp = new TradeProp();
                tradeProp.setName(entry.getKey());
                tradeProp.setValue(entry.getValue());
                tradeProp.setTradeId(tradeId);
                tradeProp.setCreateTime(TimeUtils.now());
                tradeProp.setUpdateTime(TimeUtils.now());
                tradePropList.add(tradeProp);
            }
            tradePropService.insertBatch(tradePropList) ;
        }

        return Arrays.asList(changeRecord,relChangeRecord);


    }

    @Override
    public void decreaseBalance(Long mainAccountId, BigDecimal amount,String remark) {
        decreaseBalance(mainAccountId,amount,remark,true);
    }

    private void decreaseBalance(Long mainAccountId, BigDecimal amount , String remark , boolean check ) {
        RLock lock = redisson.getLock(String.format("mainAccountId:%d", mainAccountId));
        if(lock.tryLock()){
            try{
                MainAccount mainAccount = mainAccountService.findById(mainAccountId);
                amount.divide(BigDecimal.ONE,10,BigDecimal.ROUND_HALF_UP );
                if(check && BigDecimals.compare(mainAccount.getBalanceAmount(), amount ) < 0){
                    throw new BusException("账户余额不足");
                }
                MainAccount update = new MainAccount();
                update.setBalanceAmount(mainAccount.getBalanceAmount().subtract(amount));
                Example<MainAccount> example = MainAccount.createExample();
                example.createCriteria().andEqualTo("mainAccountId",mainAccount.getMainAccountId())
                        .andEqualTo("balanceAmount" ,mainAccount.getBalanceAmount());
                mainAccountService.updateSelectiveByExample(update,example);

                BalanceChange balanceChange = new BalanceChange();
                balanceChange.setMainAccountId(mainAccountId);
                balanceChange.setAmount(amount.multiply(BigDecimal.valueOf(-1)));
                balanceChange.setRemark(remark);
                balanceChange.setCreateTime(TimeUtils.now());
                balanceChange.setUpdateTime(TimeUtils.now());
                balanceChangeService.insert(balanceChange);
            }finally {
                lock.unlock();
            }
        }


    }

    @Override
    public void decreaseBalanceWithNotCheck(Long mainAccountId, BigDecimal amount,String remark) {
        decreaseBalance(mainAccountId,amount,remark,false );
    }

    @Override
    public void increaseBalance(Long mainAccountId, BigDecimal amount,String remark) {
        RLock lock = redisson.getLock(String.format("mainAccountId:%d", mainAccountId ));
        if (lock.tryLock()) {
            try {
                MainAccount mainAccount = mainAccountService.findById(mainAccountId);

                MainAccount update = new MainAccount();
                update.setBalanceAmount(mainAccount.getBalanceAmount().add(amount));
                Example<MainAccount> example = MainAccount.createExample();
                example.createCriteria().andEqualTo("mainAccountId",mainAccount.getMainAccountId())
                        .andEqualTo("balanceAmount" ,mainAccount.getBalanceAmount());
                mainAccountService.updateSelectiveByExample(update,example);
                BalanceChange balanceChange = new BalanceChange();
                balanceChange.setMainAccountId(mainAccountId);
                balanceChange.setAmount(amount);
                balanceChange.setRemark(remark);
                balanceChange.setCreateTime(TimeUtils.now());
                balanceChange.setUpdateTime(TimeUtils.now());
                balanceChangeService.insert(balanceChange);

            }finally {
                lock.unlock();
            }
        }


    }

    @Override
    public List<ChangeRecord> findChangeRecordsByTradeIdSubjectDirection(Long trackingId, String subject, Integer direction ) {
        Example<ChangeRecord> example = ChangeRecord.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("trackingId" , trackingId ).andEqualTo("subject" , subject).andEqualTo("direction" ,direction );
        return changeRecordService.findListByExample(example);
    }

    @Transactional
    @Override
    public void bookConsumeCourse(Date lectureDate,Long mainAccountId, BigDecimal amount, String remark, Long classId, Long classLectureId, Long regId , Long studentId ) {
        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("classId" , String.valueOf(classId));
        tradeProps.put("regId" , String.valueOf(regId));
        tradeProps.put("classLectureId" , String.valueOf(classLectureId));
        tradeProps.put("studentId" , String.valueOf(studentId));
        book(regId ,lectureDate, mainAccountId, amount , 1 , "【" + remark + "】收入", Subjects.FUTURE_INCOME,IncomeCategoryEnum.COURSE_INCOME.id, mainAccountId, amount, 0, "【" + remark + "】营收", Subjects.REAL_INCOME,IncomeCategoryEnum.COURSE_INCOME.id , tradeProps );
    }

    @Transactional
    @Override
    public void bookTeacherCost(Date lectureDate,Long mainAccountId, Long relMainAccountId, BigDecimal amount, String remark , Long classId , Long classLectureId ,Integer lectureNo, Long teacherId ) {
        Map<String,String> tradeProps = new HashMap<>();
        tradeProps.put("classId" , String.valueOf(classId));
        tradeProps.put("classLectureId" , String.valueOf( classLectureId ) );
        tradeProps.put("teacherId" , String.valueOf(teacherId) );
        tradeProps.put("lectureNo" , String.valueOf(lectureNo) );

        RelFeeCategoryIncomeCategory relFeeCategoryIncomeCategory = relFeeCategoryIncomeCategoryService.findById(FeeCategoryEnum.SALARY_OF_COURSE.id);
        book(classId,lectureDate,mainAccountId, amount,0,remark , Subjects.COST,FeeCategoryEnum.SALARY_OF_COURSE.id, relMainAccountId, amount , 0 , remark , Subjects.FUTURE_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() , tradeProps );
        book(classId,lectureDate,relMainAccountId, amount,1, remark, Subjects.FUTURE_INCOME, relFeeCategoryIncomeCategory.getIncomeCategoryId() , relMainAccountId, amount , 0 , remark , Subjects.REAL_INCOME ,relFeeCategoryIncomeCategory.getIncomeCategoryId() , tradeProps );
    }


    @Override
    public MainAccount findMainAccount(Long mainAccountId) {
        return mainAccountService.findById(mainAccountId);
    }

    @Transactional
    @Override
    public void checkDifferenceConsume(Long mainAccountId , Long regId , Long classId ,String className , Long studentId,List<Long> classLectureIds ) {
        List<ChangeRecord> changeRecordList = changeRecordService.findChangeRecordByTrackingIdSubjectCategoryId(regId, Subjects.FUTURE_INCOME , IncomeCategoryEnum.COURSE_INCOME.id);
        BigDecimal futureAmount  = BigDecimal.ZERO ;
        BigDecimal amountOfDeb = BigDecimal.ZERO ;
        for(ChangeRecord changeRecord : changeRecordList ){
            if(changeRecord.getDirection() == 1 ){
                amountOfDeb = amountOfDeb.add(changeRecord.getAmount());
            }else{
                futureAmount = futureAmount.add(changeRecord.getAmount());
            }
        }

        BigDecimal differenceAmount = futureAmount.subtract(amountOfDeb);

        if(BigDecimals.compare(differenceAmount , BigDecimal.ZERO ) > 0 ){
            Map<String,String> tradeProps = new HashMap<>();
            tradeProps.put("classId" , String.valueOf(classId));
            tradeProps.put("regId" , String.valueOf(regId));
            tradeProps.put("studentId" , String.valueOf(studentId));
            tradeProps.put("differenceClassLectureIds" , StringUtils.join(classLectureIds,","));
            book(regId ,TimeUtils.now(), mainAccountId, differenceAmount , 1 , "【"+className+"|消耗差额】收入", Subjects.FUTURE_INCOME,IncomeCategoryEnum.COURSE_INCOME.id, mainAccountId, differenceAmount, 0, "【消耗差额】营收", Subjects.REAL_INCOME,IncomeCategoryEnum.COURSE_INCOME.id , tradeProps );

        }


    }
}
